package com.kpf.springcloud.service.impl;

import com.kpf.springcloud.mapper.TokenMapper;
import com.kpf.springcloud.pojo.JwtUtil;
import com.kpf.springcloud.pojo.KpfAccountToken;
import com.kpf.springcloud.pojo.KpfUser;
import com.kpf.springcloud.service.IKpfUserService;
import com.kpf.springcloud.service.ITokenService;
import com.kpf.springcloud.utils.GeneralUtil;
import com.kpf.springcloud.utils.LocalIpUtils;
import com.kpf.springcloud.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @author shiwen
 * @date 2021/2/28
 */
@Service
public class TokenServiceImpl extends BaseServiceImpl<TokenMapper, KpfAccountToken> implements ITokenService {

    private Logger logger = LoggerFactory.getLogger(KpfUserServiceImpl.class);

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IKpfUserService userService;

    /**
     * 创建token
     *
     * @param userId
     * @param roleType
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createToken(int userId, int roleType) {
        // 这里roleType主要是方便获取解析的时候进行权限判断用的. subject先空着不用
        String token = jwtUtil.createJWT(userId + "", "", roleType);
        Date expirationTime = jwtUtil.parseJWT(token).getExpiration();
        KpfAccountToken accountToken = KpfAccountToken.builder().userId(userId).expires(expirationTime.getTime()).token(token).build();
        // 创建token并入库
        boolean save = save(accountToken);
        if (save) {
            stringRedisTemplate.opsForValue().set(LocalIpUtils.getLocalIpAddr() + ":userId", userId + "");
            logger.info("createToken userId = {}", userId);
        }
        return save;
    }

    /**
     * 校验当前userId的token是否有效, 若无效则需要登录, 这里可以让前端传一个token进来, 不用存redis
     */
    @Override
    public String verifyToken() {
        // 充redis里面获取最新的userId - 单机
        String userId = stringRedisTemplate.opsForValue().get(LocalIpUtils.getLocalIpAddr() + ":userId");
        logger.info("verifyToken init success！userId = " + userId);
        if (GeneralUtil.isObjNull(userId)) {
            // 若不存在userId, 则需要先登录
            return "TOKEN_EXPIRED";
        }
        // 如果userId仍存在则直接获取token
        if (GeneralUtil.isObjNotNullAndZero(userId)) {
            List<KpfAccountToken> kpfAccountTokens = list(getInitQueryWrapper().eq(KpfAccountToken::getUserId, userId)
                    .orderByDesc(KpfAccountToken::getCreated));
            if (GeneralUtil.isListNull(kpfAccountTokens)) {
                stringRedisTemplate.delete(LocalIpUtils.getLocalIpAddr() + ":userId");
                // 不存在token则需要重新登录
                return "TOKEN_EXPIRED";
            }
            // 最新token
            KpfAccountToken accountToken = kpfAccountTokens.get(0);
            Long currentTimeMillis = System.currentTimeMillis();
            // 当前时间大于token过期时间的时候, 才是过期
            if (currentTimeMillis.compareTo(accountToken.getExpires()) > 0) {
                stringRedisTemplate.delete(LocalIpUtils.getLocalIpAddr() + ":userId");
                // token过期也需要重新登录
                return "TOKEN_EXPIRED";
            }
            // 返回有效的userId, 这里需要判断是否已经充值
            KpfUser kpfUser = userService.getById(userId);
            return TokenUtils.parseToken(accountToken.getToken()) + "-" + kpfUser.getUserType();
        }
        // 如果token不存在或者已经过期则直接清空线程池里面的userId
        stringRedisTemplate.delete(LocalIpUtils.getLocalIpAddr() + ":userId");
        return "TOKEN_EXPIRED";
    }

    /**
     * 注销登录：去除redis里面的数据，当userId为空的时候重新调用verifyToken直接重新登陆
     */
    @Override
    public void loginOut() {
        // 1、清空redis里面的userId
        stringRedisTemplate.delete(LocalIpUtils.getLocalIpAddr() + ":userId");
    }

}